using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace SurvivalStrategy.PathFinding
{
    public enum Heuristic
    {
        Manhatan,
        Distance
    }
    class AStar
    {
        private PathMap pathMap;

        private PathNode startPosition;
        private PathNode endPosition;

        private List<PathNode> openList;
        private List<PathNode> path;
        public Heuristic heuristic { get; set; }

        private bool ready;

        public List<PathNode> Path
        {
            get { return path; }
        }

        public AStar(PathMap map)
        {
            this.pathMap = map;
            openList = new List<PathNode>();
            path = new List<PathNode>();
            this.heuristic = Heuristic.Manhatan;
        }

        public void UpdateStart(Vector2 startPosition)
        {
            this.startPosition = new PathNode(this.pathMap, startPosition);
        }

        public void UpdateEnd(Vector2 endPosition)
        {
            this.endPosition = new PathNode(this.pathMap, endPosition);
        }

        public void Search()
        {
            openList.Clear();
            path.Clear();
            PathNode nextNode = startPosition;
            do
            {
                openList.Add(nextNode);

                PathNode tempNode = FindNextNode(nextNode);

                openList.Remove(nextNode);
                if (path.Find(o => o.Position == nextNode.Position) != null)
                {
                    openList.Clear();
                    break;
                }
                else
                {
                    path.Add(nextNode);

                    nextNode = tempNode;
                    openList.Add(nextNode);
                }
              
            } while ((nextNode.Position.X != endPosition.Position.X) || (nextNode.Position.Y != endPosition.Position.Y));

            path.Add(nextNode);
        }

        private PathNode FindNextNode(PathNode node)
        {
            PathNode result = new PathNode(this.pathMap);
            result.Cost = int.MaxValue;

            foreach (PathNode neighbour in node.NeighbourNodes)
            {
                if (neighbour.Position == node.Position)
                    continue;
                neighbour.Cost = node.Cost + (int)Vector2.Distance(neighbour.Position, node.Position);
                if (heuristic == Heuristic.Distance)
                    neighbour.Heuristic = DistanceHeuristic(neighbour);
                if (heuristic == Heuristic.Manhatan)
                    neighbour.Heuristic = ManchatanHeuristic(neighbour);

                if (neighbour.Value < result.Value)
                    result = neighbour;
            }
            return result;
        }

        private int ManchatanHeuristic(PathNode node)
        {
            return (int)(Math.Abs(node.Position.X - endPosition.Position.X) + Math.Abs(node.Position.Y - endPosition.Position.Y));
        }

        private int DistanceHeuristic(PathNode node)
        {
            return (int)(Math.Sqrt((node.Position.X - endPosition.Position.X) * (node.Position.X - endPosition.Position.X) + (node.Position.Y - endPosition.Position.Y) * (node.Position.Y - endPosition.Position.Y)));
        }

        public void ClearPath()
        {
            this.path = new List<PathNode>();
        }
    }
}